import axios from "axios";
import type {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  AxiosError,
  InternalAxiosRequestConfig
} from "axios";

// 定义响应数据格式
interface ResponseData<T extends object> {
  code: number;
  message: string;
  data: T;
}

// 扩展axios请求配置，加入自定义配置
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
  showError?: boolean;
}

// 获取环境变量
const env = import.meta.env;
//console.log("Environment variables:", env);
const instanceOptions = {
  baseURL: env.VITE_API_URL,
  timeout: 10000,
  showError: true // 全局默认显示错误提示
};

class HttpRequest {
  private instance: AxiosInstance;
  private readonly options: CustomAxiosRequestConfig;

  constructor(options: CustomAxiosRequestConfig = {}) {
    this.instance = axios.create({
      baseURL: options.baseURL || "",
      timeout: options.timeout || 15000,
      headers: options.headers || {}
    });
    this.options = options;

    this.setupInterceptors();
  }

  // 设置拦截器
  private setupInterceptors() {
    // 请求拦截器
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        // 在发送请求之前做处理（例如添加token）
        const token = localStorage.getItem("token");
        if (token) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      },
      (error: AxiosError) => {
        return Promise.reject(error);
      }
    );

    // 响应拦截器
    this.instance.interceptors.response.use(
      (response: AxiosResponse<ResponseData<object>>) => {
        console.log("response=====", response);
        const res = response.data;
        // 处理业务逻辑错误
        if (res.code !== 200) {
          this.handleError(response.config, res.message);
          return Promise.reject(new Error(res.message || "Error"));
        }
        return response;
      },
      (error: AxiosError) => {
        const response = error.response;
        // 处理HTTP状态码
        if (response) {
          this.handleHttpError(response.status, response.config);
        } else if (error.request) {
          // 请求已发出但没有收到响应
          this.handleNetworkError();
        } else {
          // 发送请求时出错
          this.handleRequestError(error.message);
        }
        return Promise.reject(error);
      }
    );
  }

  // 处理HTTP错误状态码
  private handleHttpError(status: number, config?: CustomAxiosRequestConfig) {
    const showError = config?.showError ?? this.options.showError ?? true;
    if (!showError) return;

    const errorMap: Record<number, string> = {
      200: "服务器成功返回请求的数据。",
      201: "新建或修改数据成功。",
      202: "一个请求已经进入后台排队（异步任务）。",
      204: "删除数据成功。",
      400: "发出的请求有错误，服务器没有进行新建或修改数据的操作。",
      401: "用户没有权限（令牌、用户名、密码错误）。",
      403: "无权访问。",
      404: "发出的请求针对的是不存在的记录，服务器没有进行操作。",
      405: "发出的请求，确保和服务器端的请求方法一致，确认是GET、POST、PUT、DELETE等。",
      406: "请求的格式不可得。",
      410: "请求的资源被永久删除，且不会再得到的。",
      422: "当创建一个对象时，发生一个验证错误。",
      500: "服务器发生错误，请检查服务器。",
      502: "网关错误。",
      503: "服务不可用，服务器暂时过载或维护。",
      504: "网关超时。"
    };

    const message = errorMap[status] || `网络错误（${status}）`;
    this.showError(message);

    // 特殊状态码处理
    if (status === 401) {
      // 跳转到登录页
      window.location.href = "/login";
    }
  }

  // 处理网络错误
  private handleNetworkError() {
    this.showError("网络异常，请检查网络连接");
  }

  // 处理请求错误
  private handleRequestError(message: string) {
    this.showError(`请求错误：${message}`);
  }

  // 处理业务错误
  private handleError(
    config: CustomAxiosRequestConfig | undefined,
    message: string
  ) {
    const showError = config?.showError ?? this.options.showError ?? true;
    if (showError) {
      this.showError(message);
    }
  }

  // 显示错误提示（可根据UI库替换实现）
  private showError(message: string) {
    console.error(message);
    // 这里可以替换为UI组件的提示方法，例如：message.error(message);
    alert(message);
  }

  // 封装请求方法
  public request<T>(config: CustomAxiosRequestConfig): Promise<T> {
    return this.instance.request(config);
  }

  /**
   * 
   * @param url 
   * @param params 
   * @param config 
   * @returns 返回的都是Promise类型，需要使用.then()或async/await来处理返回的数据
   * 
   * // 基本用法
      const params = { name: "John", age: 30 };
      http.get<UserInfo>("/user/info", params)
      .then((data) => {
        console.log("用户信息:", data);
      })
      .catch((error) => {
        // 错误已统一处理，这里可以处理特殊逻辑
        console.error(error);
      });
   */
  public get<T>(
    url: string,
    params?: Record<string, string | number | object>,
    config?: CustomAxiosRequestConfig
  ): Promise<T> {
    return this.instance.get(url, { ...config, params });
  }

  /**
   * 发送一个 POST 请求
   * @param url - 请求的 URL 地址
   * @param data - 要发送的数据，可选参数
   * @param config - 自定义的 Axios 请求配置，可选参数，可包含如超时时间、请求头等配置，还可设置是否显示错误提示
   * @returns 返回一个 Promise 对象，该对象解析为请求响应的数据，数据类型由泛型 T 定义
   *
   * // 基本用法
   * const postData = { name: "Jane", age: 25 };
   * http.post<UserInfo>("/user/create", postData)
   *   .then((data) => {
   *     console.log("创建用户成功:", data);
   *   })
   *   .catch((error) => {
   *     // 错误已统一处理，这里可以处理特殊逻辑
   *     console.error(error);
   *   });
   */
  public post<T>(
    url: string,
    data?: object,
    config?: CustomAxiosRequestConfig
  ): Promise<T> {
    return this.instance.post(url, data, config);
  }

  public put<T>(
    url: string,
    data?: object,
    config?: CustomAxiosRequestConfig
  ): Promise<T> {
    return this.instance.put(url, data, config);
  }

  public delete<T>(url: string, config?: CustomAxiosRequestConfig): Promise<T> {
    return this.instance.delete(url, config);
  }

  /**
   * 文件上传
   * @param url 上传地址
   * @param file 文件对象
   * @param data 其他表单数据
   * @param config 配置项
   * // 基本用法
      const file = new File(['content'], 'test.txt');
      http.upload('/api/upload', file);

      // 带额外数据
      const file = new File(['content'], 'test.txt');
      http.upload('/api/upload', file, {
        name: 'test',
        type: 1,
        description: 'test file'
      });

      // 带自定义配置
      const file = new File(['content'], 'test.txt');
      http.upload('/api/upload', file, {
        name: 'test'
      }, {
        headers: {
          'X-Custom-Header': 'value'
        },
        onUploadProgress: (progressEvent) => {
          console.log('上传进度:', progressEvent);
        }
      });
   */
  public upload<T>(
    url: string,
    file: File,
    data?: Record<string, string | number | Blob>,
    config?: CustomAxiosRequestConfig
  ): Promise<T> {
    const formData = new FormData();
    formData.append("file", file);

    // 添加其他表单数据
    if (data) {
      Object.entries(data).forEach(([key, value]) => {
        // 将数字转换为字符串
        const formValue = typeof value === "number" ? value.toString() : value;
        formData.append(key, formValue);
      });
    }

    return this.instance.post(url, formData, {
      ...config,
      headers: {
        "Content-Type": "multipart/form-data",
        ...config?.headers
      }
    });
  }
}
export default new HttpRequest(instanceOptions);
